﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using SharePoint.Orm.Attributes;

namespace SharePoint.Orm.Helpers {
	/// <summary>
	/// Helpers for working with SPOrm attributes.
	/// </summary>
	public class SPOrmAttributeHelper {
		/// <summary>
		/// Gets the <see cref="SPOrmContentTypeAttribute"/> on a type.
		/// </summary>
		/// <param name="contentType">The type to get the attribute on.</param>
		/// <returns>The attribute.</returns>
		public static SPOrmContentTypeAttribute GetContentTypeAttribute(Type contentType) {
			object[] contentTypeAttrs = contentType.GetCustomAttributes(typeof(SPOrmContentTypeAttribute), true);
			if (contentTypeAttrs.Length == 0) {
				throw new Exception("Could not find attribute 'SPOrmContentType' on type '" + contentType.FullName + "'");
			}
			SPOrmContentTypeAttribute contentTypeAttr = (SPOrmContentTypeAttribute)contentTypeAttrs[0];
			return contentTypeAttr;
		}

		/// <summary>
		/// Gets the <see cref="SPOrmContentTypeAttribute"/> on a type.
		/// </summary>
		/// <typeparam name="TContentType">The type to get the attribute on</typeparam>
		/// <returns>The attribute</returns>
		public static SPOrmContentTypeAttribute GetContentTypeAttribute<TContentType>() {
			return GetContentTypeAttribute(typeof(TContentType));
		}

		/// <summary>
		/// Gets the <see cref="SPOrmListAttribute"/> on a type.
		/// </summary>
		/// <param name="list">The type to get the attribute on</param>
		/// <returns>The attribute</returns>
		public static SPOrmListAttribute GetListAttribute(Type list) {
			object[] listAttrs = list.GetCustomAttributes(typeof(SPOrmListAttribute), true);
			if (listAttrs.Length == 0) {
				throw new Exception("Could not find attribute 'SPOrmList' on type '" + list.FullName + "'");
			}
			SPOrmListAttribute listAttr = (SPOrmListAttribute)listAttrs[0];
			return listAttr;
		}

		/// <summary>
		/// Gets the <see cref="SPOrmListAttribute"/> on a type.
		/// </summary>
		/// <typeparam name="TList">The type to get the attribute on</param>
		/// <returns>The attribute</returns>
		public static SPOrmListAttribute GetListAttribute<TList>() {
			return GetListAttribute(typeof(TList));
		}

		/// <summary>
		/// Gets the <see cref="SPOrmFieldAttribute"/> on a property.
		/// </summary>
		/// <typeparam name="T">The type the property belongs to.</typeparam>
		/// <param name="exp">The expression referencing the field. (eg o=>o.Title)</param>
		/// <returns>The attribute.</returns>
		public static SPOrmFieldAttribute GetFieldAttribute<T>(Expression<Func<T, object>> exp) {
			MemberExpression memberExpression;
			if (exp.Body is UnaryExpression) {
				memberExpression = (MemberExpression)((UnaryExpression)exp.Body).Operand;
			} else {
				memberExpression = (MemberExpression)exp.Body;
			}
			PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;
			return propertyInfo.GetCustomAttributes(typeof(SPOrmFieldAttribute), true).Cast<SPOrmFieldAttribute>().FirstOrDefault();
		}
	}
}
